/*
*  14.3.2011 L��v�k Bjarnason
*
* Copyright (c) L��v�k Bjarnason
*
*/

import javax.swing.text.html.HTMLDocument;
import java.io.*;
import java.net.*;
import java.util.Date;

public class ClientThread implements Runnable {

    Socket m_clientSocket;
    Thread runner;

    public ClientThread(Socket clientSocket) {
        this.m_clientSocket = clientSocket;
        runner = new Thread(this); // (1) Create a new thread.
        System.out.println(runner.getName());
        runner.start(); // (2) Start the thread.

    }

    public void run() {

        // Obtain the input stream and the output stream for the socket
        // A good practice is to encapsulate them with a BufferedReader
        // and a PrintWriter as shown below.


        // Print out details of this connection
        System.out.println("Accepted Client : Address - " +
                m_clientSocket.getInetAddress().getHostName());

        try {

            BufferedReader in = new BufferedReader(new InputStreamReader(m_clientSocket.getInputStream()));
            OutputStream out = new BufferedOutputStream(m_clientSocket.getOutputStream());
            PrintStream pout = new PrintStream(out);
            // read first line of request (ignore the rest)
            String request = in.readLine();

            log(m_clientSocket, request);


            // parse the line
            if (!request.startsWith("GET") || request.length() < 14 ||
                    !(request.endsWith("HTTP/1.0") || request.endsWith("HTTP/1.1"))) {
                // bad request
                errorReport(pout, m_clientSocket, "400", "Bad Request",
                        "Your browser sent a request that " +
                                "this server could not understand.");
            } else {
                String req = request.substring(5, request.length() - 9).trim();
                if (req.indexOf("..") != -1 ||
                        req.indexOf("/.ht") != -1 || req.endsWith("~")) {
                    errorReport(pout, m_clientSocket, "403", "Forbidden",
                            "You don't have permission to access the requested URL.");
                } else {
                    String path = req;
                    File f = new File(path);
                    if (f.isDirectory() && !path.endsWith("/")) {
                        // redirect browser if referring to directory without final '/'
                        pout.print("HTTP/1.0 301 Moved Permanently\r\n" +
                                "Location: http://" +
                                m_clientSocket.getLocalAddress().getHostAddress() + ":" +
                                m_clientSocket.getLocalPort() + "/" + req + "/\r\n\r\n");
                        log(m_clientSocket, "301 Moved Permanently");
                    } else {

                        try {
                            if (req.contains("allCaps")) {
                                String s = req.substring(19);
                                String upperCase = s.toUpperCase();
                                output(upperCase, out);
                            }
                            if (req.contains("addNumbers")) {

                                String s = req.substring(22);
                                String[] arr = s.split("\\+");
                                char[] stringArray = s.toCharArray();

                                System.out.println(arr[0]);

                                if (Character.isDigit(stringArray[0])) {
                                    if (arr.length == 2) {
                                        int sum = Integer.parseInt(arr[0]) + Integer.parseInt(arr[1]);
                                        output(sum, out);
                                    } else {
                                        String errorMessage = "please type two numbers, with space";
                                        output(errorMessage, out);
                                    }
                                } else {
                                    String digErr = "not integer - cannot calculate";
                                    output(digErr, out);

                                }


                            }
                            if (req.contains("jvmStatus")) {
                                //Getting the runtime reference from system
                                int megaBytes = 1024 * 1024;
                                Runtime runtime = Runtime.getRuntime();
                                String s = ("Used Memory: "
                                        + ((runtime.totalMemory() - runtime.freeMemory()) / megaBytes)) + "\r\n"

                                        + ("Free Memory: "
                                        + runtime.freeMemory() / megaBytes) + "\r\n"
                                        + ("Total Memory: "
                                        + runtime.totalMemory() / megaBytes) + "\r\n"
                                        + ("Max Memory: "
                                        + runtime.maxMemory() / megaBytes) + "\r\n";

                                output(s, out);


                            }


                            // send file
                            InputStream file = new FileInputStream(f);
                            pout.print("HTTP/1.0 200 OK\r\n" +
                                    "Content-Type: " + guessContentType(path) + "\r\n" +
                                    "Date: " + new Date() + "\r\n" +
                                    "Server: FileServer 1.0\r\n\r\n");
                            sendFile(file, out); // send raw file
                            log(m_clientSocket, "200 OK");
                        } catch (FileNotFoundException e) {

                        }
                    }
                }
            }
            out.flush();
        } catch (IOException e) {
            System.err.println(e);
        }
        try {
            if (m_clientSocket != null) {
                m_clientSocket.close();
                if (runner != null) {

                    runner.interrupt();
                }
            }
        } catch (IOException e) {
            System.err.println(e);
        }
    }

    private static void log(Socket m_clientSocket, String msg) {
        System.err.println(new Date() + " [" + m_clientSocket.getInetAddress().getHostAddress() +
                ":" + m_clientSocket.getPort() + "] " + msg);
    }

    private static void output(Object toDisplay, OutputStream out) throws IOException {
        //We output html string with method call
        StringBuilder strengur = new StringBuilder();
        strengur.append("\r\n" +
                "<TITLE>" + "</TITLE>\r\n" +
                "</HEAD><BODY>\r\n" +
                "<H1>" + toDisplay + "</H1>\r\n" +
                "</BODY></HTML>\r\n");

        out.write(strengur.toString().getBytes());
        out.flush();


    }


    private static void errorReport(PrintStream pout, Socket m_clientSocket,
                                    String code, String title, String msg) {
        pout.print("HTTP/1.0 " + code + " " + title + "\r\n" +
                "\r\n" +
                "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n" +
                "<TITLE>" + code + " " + title + "</TITLE>\r\n" +
                "</HEAD><BODY>\r\n" +
                "<H1>" + title + "</H1>\r\n" + msg +
                "<HR><ADDRESS>FileServer 1.0 at " +
                m_clientSocket.getLocalAddress().getHostName() +
                " Port " + m_clientSocket.getLocalPort() + "</ADDRESS>\r\n" +
                "</BODY></HTML>\r\n");
        log(m_clientSocket, code + " " + title);
    }

    private static String guessContentType(String path) {
        if (path.endsWith(".html") || path.endsWith(".htm"))
            return "text/html";
        else if (path.endsWith(".txt") || path.endsWith(".java"))
            return "text/plain";
        else if (path.endsWith(".gif"))
            return "image/gif";
        else if (path.endsWith(".class"))
            return "application/octet-stream";
        else if (path.endsWith(".jpg") || path.endsWith(".jpeg"))
            return "image/jpeg";
        else
            return "text/plain";
    }

    private static void sendFile(InputStream file, OutputStream out) {
        try {
            byte[] buffer = new byte[1000];
            while (file.available() > 0)
                out.write(buffer, 0, file.read(buffer));
        } catch (IOException e) {
            System.err.println(e);
        }
    }
}



